package com.xuhuan.demo.file;

import com.xuhuan.demo.uuid.UuidUtil;
import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * @Author huan.xu
 * @Date 2023/6/16 10:25
 * @Description 文件切割工具类
 */
@Slf4j
public class FileSplitUtil {
    /**
     * 单个文件大小，1024表示kb，
     */
    private static final int FILE_SIZE = 1024 * 500;

    /**
     * 子文件下标
     */
    private static final int FILE_NAME_EXT = 1;

    /**
     * 文件结束标识
     */
    private static final int EOF = -1;

    /**
     * 分片文件组成部分
     */
    private static final String SPLIT_FILE_NAME = "-split.";

    /**
     * 匹配分片文件占位符
     */
    private static final String PLACEHOLDER = "zzz";

    /**
     * 文件分片
     *
     * @param srcFile      待分片的源文件
     * @param outPutDir    分片的输出目录
     * @param compressType 压缩类型(文件后缀-可自行决定)
     * @throws IOException 异常
     */
    public static void split(File srcFile, String outPutDir, String compressType) throws IOException {
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(srcFile));

        int saveSize = FILE_SIZE;
        byte[] bytes = new byte[saveSize];

        int length;
        // 子文件下标
        int filenameExt = FILE_NAME_EXT;
        while ((length = bis.read(bytes)) > EOF) {
            int ext = filenameExt++;
            try {
                String fileName=outPutDir + ext + SPLIT_FILE_NAME + compressType;
                log.info(fileName);
                FileOutputStream fileOutputStream = new FileOutputStream(fileName);
                BufferedOutputStream bos = new BufferedOutputStream(fileOutputStream);
                bos.write(bytes, 0, length);
            } catch (Exception e) {

            }
        }
        bis.close();
    }

    /**
     * 合并分片文件 默认将合并后的文件放在其分片文件所在目录, 可行性决定
     *
     * @param sliceDir     所有分片文件所在目录
     * @param compressType 压缩类型(文件后缀-可自行决定)
     * @throws IOException 异常
     */
    public static void merge(String sliceDir, String compressType) throws IOException {
        List<String> subFileNames = getSplitFileNames(sliceDir, compressType);
        if (subFileNames.size() < 1) {
            throw new RuntimeException("目录下没有分片文件...");
        }

        BufferedOutputStream bos = new BufferedOutputStream(
                new FileOutputStream(sliceDir + UuidUtil.getUuid() + "." + compressType));
        for (String subFilename : subFileNames) {
            try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(sliceDir + subFilename))) {
                // 每次读取1Mb大小的文件
                byte[] bytes = new byte[FILE_SIZE];
                int length;
                while ((length = bis.read(bytes)) > EOF) {
                    bos.write(bytes, 0, length);
                }
                bos.flush();
            } finally {
                File eachSubFile = new File(sliceDir + subFilename);
                if (eachSubFile.exists() && eachSubFile.delete()) {
                    log.info("删除分片文件成功...");
                }
            }
        }
        bos.close();
    }

    /**
     * 获取目录下的所有分片文件名
     *
     * @param sliceDir     源目录
     * @param compressType 压缩类型(文件后缀-可自行决定)
     * @return 结果
     */
    public static List<String> getSplitFileNames(String sliceDir, String compressType) {
        File file = new File(sliceDir);
        if (!file.isDirectory()) {
            throw new RuntimeException("不是一个目录...");
        }

        String[] list = file.list();
        if (list == null || list.length == 0) {
            throw new RuntimeException("目录下没有任何文件...");
        }

        // 这里zzz为通用占位符、匹配分片文件
        String filename = (PLACEHOLDER + SPLIT_FILE_NAME + compressType).replace(PLACEHOLDER, "\\d+");
        return Arrays.stream(list)
                .filter(s -> s.matches(filename))
                .sorted()
                .collect(Collectors.toList());
    }

    public static void main(String[] args) throws IOException {
        String filePath = "C:\\Users\\Administrator\\Desktop\\file-split\\pp.jpg";
        String splitOutPutDir = "C:\\Users\\Administrator\\Desktop\\file-split\\split\\";
        String mergeOutPutDir = "C:\\Users\\Administrator\\Desktop\\file-split\\merge\\";
        // 分片
        split(new File(filePath), splitOutPutDir, "jpg");

        //合并
//        merge(outPutDir, "jpg");
    }
}
